#include "ringbuffer.h"
#include <stdlib.h>
#include <string.h>

ringbuffer_t ringbuffer_creat(size_t size)
{
    if (size < 2) return NULL;
    ringbuffer_t rb = (ringbuffer_t)malloc(sizeof(_ringbuffer_t));
    if (!rb) return NULL;
    rb->buffer = (uint8_t *)malloc(size);
    if (!rb->buffer) {
        free(rb);
        return NULL;
    }
    rb->size = size;
    rb->head = rb->tail = 0;
    return rb;
}

int ringbuffer_destroy(ringbuffer_t rb)
{
    if (!rb) return -1;
    if (rb->buffer) free(rb->buffer);
    rb->buffer = NULL;
    rb->size = 0;
    rb->head = rb->tail = 0;
    free(rb);
    return 0;
}

int ringbuffer_init(ringbuffer_t rb, uint8_t *buffer, size_t size)
{
    if (!rb || !buffer || size < 2) return -1;
    rb->buffer = buffer;
    rb->size = size;
    rb->head = rb->tail = 0;
    return 0;
}

int ringbuffer_write(ringbuffer_t rb, const uint8_t *data, size_t len)
{
    if (!rb || !data || len == 0) return -1;
    size_t i = 0;
    while (i < len) {
        // 计算本次可批量写入的长度
        size_t space = (rb->tail > rb->head) ? (rb->tail - rb->head - 1) : (rb->size - rb->head);
        if (space == 0) space = rb->size - rb->head;
        size_t write_len = (len - i < space) ? (len - i) : space;
        if (write_len == 0) write_len = 1; // 至少写1字节（覆盖模式）
        // 写入数据
        memcpy(&rb->buffer[rb->head], &data[i], write_len);
        rb->head = (rb->head + write_len) % rb->size;
        i += write_len;
        // 覆盖模式，head追上tail时，tail前移
        if (rb->head == rb->tail) {
            rb->tail = (rb->tail + write_len) % rb->size;
        }
    }
    return (int)i;
}

int ringbuffer_read(ringbuffer_t rb, uint8_t *data, size_t len)
{
    if (!rb || !data || len == 0) return -1;
    int avail = ringbuffer_available(rb);
    if (avail <= 0) return 0;
    if ((size_t)avail < len) len = avail;
    size_t i = 0;
    while (i < len) {
        size_t chunk = (rb->head > rb->tail) ? (rb->head - rb->tail) : (rb->size - rb->tail);
        if (chunk > len - i) chunk = len - i;
        memcpy(&data[i], &rb->buffer[rb->tail], chunk);
        rb->tail = (rb->tail + chunk) % rb->size;
        i += chunk;
    }
    return (int)i;
}

int ringbuffer_available(ringbuffer_t rb)
{
    if (!rb) return -1;
    if (rb->head >= rb->tail)
        return (int)(rb->head - rb->tail);
    else
        return (int)(rb->size - rb->tail + rb->head);
}

int ringbuffer_space(ringbuffer_t rb)
{
    if (!rb) return -1;
    int avail = ringbuffer_available(rb);
    if (avail < 0) return -1;
    return (int)(rb->size - avail - 1);
}

int ringbuffer_peek(ringbuffer_t rb, uint8_t *data, size_t len)
{
    if (!rb || !data || len == 0) return -1;
    int avail = ringbuffer_available(rb);
    if (avail <= 0) return 0;
    if ((size_t)avail < len) len = avail;
    size_t i = 0, idx = rb->tail;
    while (i < len) {
        size_t chunk = (rb->head > idx) ? (rb->head - idx) : (rb->size - idx);
        if (chunk > len - i) chunk = len - i;
        memcpy(&data[i], &rb->buffer[idx], chunk);
        idx = (idx + chunk) % rb->size;
        i += chunk;
    }
    return (int)i;
}

int ringbuffer_flush(ringbuffer_t rb)
{
    if (!rb) return -1;
    rb->head = rb->tail = 0;
    return 0;
}

int ringbuffer_write_byte(ringbuffer_t rb, uint8_t data)
{
    if (!rb) return 0;
    rb->buffer[rb->head] = data;
    rb->head = (rb->head + 1) % rb->size;
    if (rb->head == rb->tail) {
        rb->tail = (rb->tail + 1) % rb->size;
    }
    return 1;
}

int ringbuffer_read_byte(ringbuffer_t rb, uint8_t *data)
{
    if (!rb || !data) return 0;
    if (rb->head == rb->tail) return 0;
    *data = rb->buffer[rb->tail];
    rb->tail = (rb->tail + 1) % rb->size;
    return 1;
}